home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / mpeg.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  21KB  |  890 lines

  1. /*
  2.  * $Id: mpeg.c,v 0.91 1994/02/20 00:52:55 zhao Pre-Release $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  *
  25.  *  Rudimentary MPEG support. Seeking is done via the brute force
  26.  *  method, that is actually reading the frames one by one.
  27.  *
  28.  *  Uses Berkeley's library with its good and evil ...
  29.  *  No sound support.
  30.  *
  31.  *  BUGS: seeking does not work correctly
  32.  */
  33. #ifndef NO_MPEG
  34.  
  35. #if !defined(lint) && defined(F_ID)
  36. char *id_mpg = "$Id: mpeg.c,v 0.91 1994/02/20 00:52:55 zhao Pre-Release $";
  37. #endif
  38.  
  39. #include "bit.h"
  40. #include "extern.h"
  41. #include "mpeg/video.h"        /* for VidStream definaitons */
  42. #include "mpeg/mlib.h"        /* for prototypes            */
  43.  
  44.  
  45. /************* Defines and limits ************************/
  46.  
  47. #define SEEKSMALL    5
  48. #define SEEKLARGE    10
  49.  
  50.  
  51. /************ Local varialbes ****************************/
  52.  
  53. static int cur_frame_no;    /* current frame number    */
  54. static int actual_frames;    /* total no. frames        */
  55. static int magfactor = 2;    /* default maginifcation   */
  56. static int current_fdelay;    /* frame delay             */
  57. static int loop_back;        /* true if play & loop     */
  58. static void *oldpic;        /* old BIT image           */
  59. static VidStream *cur_frame;    /* current video stream    */
  60.  
  61. static FL_OBJECT *fn;        /* frame number            */
  62. static IMG_IO *rgb_wio[30];    /* all RGB writing func    */
  63. static int currentwrite;    /* current selected func   */
  64. static int total_rgbwrite;
  65.  
  66.  
  67. /******************* Local functions ***************************/
  68.  
  69. static void update_frame_number(void);
  70. static FL_FORM *create_form_mpg(void);
  71. static void show_play_rate(float);
  72. static void MPEG_rewind(IPTR);
  73. static int MPEG_convert(int);
  74.  
  75. static void frame_to_bit(IPTR);
  76. static void fake_frame_to_bit(IPTR);
  77. static void frame_to_disk(void);
  78.  
  79. static void push_globals(IPTR);    /* save zoom factors etc.   */
  80. static void pop_globals(IPTR);    /* restore zoom factors etc */
  81.  
  82. static void MpegDisplay(VidStream * vid);
  83. static void MPEG_play(IPTR, int);
  84.  
  85.  
  86. /*********************************************************************
  87.  * Get dimensions and other information about MPEG. Initalize
  88.  * the decoder and other things. Due to the use of library, MPEG_desc
  89.  * may cause the 1st frame being loaded. MPEG_load will check that
  90.  ********************************************************************/
  91.  
  92. int
  93. MPEG_desc(IPTR im)
  94. {
  95.  
  96.     create_form_mpg();
  97.     set_video_stream(im->fp);
  98.     frame_re_init();
  99.     reset_mpeg_stream();
  100.  
  101.     actual_frames = 400;
  102.  
  103.     /* the first frame. Zero indicates initalization */
  104.     if (!(cur_frame = mpeg_next_frame(0)))
  105.       {
  106.       Bark("MPEG_Desc", "Something is wrong");
  107.       return -1;
  108.       }
  109.  
  110.     im->w = cur_frame->mb_width * 16;
  111.     im->h = cur_frame->mb_height * 16;
  112.  
  113.     /* tell the driver that we are dealing with multi-images */
  114.  
  115.     im->more = 1;
  116.  
  117.     cur_frame_no = 0;
  118.     update_frame_number();
  119.     return 0;
  120. }
  121.  
  122. /*****************************************************************
  123.  *  Load and show the first frame
  124.  ******************************************************************/
  125.  
  126. int
  127. MPEG_load(IPTR im)
  128. {
  129.  
  130.     /* if MPEG_desc did not load the 1st frame, load it now */
  131.  
  132.     if ((cur_frame && cur_frame->current) ||
  133.     ((cur_frame = mpeg_next_frame(1)) && cur_frame->current))
  134.       {
  135.       /* must pass im 'cause imgptr is updated AFTER xxx_load returns */
  136.       frame_to_bit(im);
  137.       }
  138.  
  139.     cur_frame_no = 1;
  140.     update_frame_number();
  141.     return (cur_frame && cur_frame->current) ? 0 : -1;
  142. }
  143.  
  144. /***********************************************************************
  145.  * After displaying the first frame, the driver will call this routine
  146.  * to load next frame. For mpeg, we take control and never return
  147.  * until the last frame or whatever the user wants to do with the
  148.  * video stream
  149.  ***********************************************************************/
  150.  
  151. /* Upon entering this routine, im and imgptr are the same thing,
  152.    so we can use them interchangaebly */
  153.  
  154. /* ARGSUSED */
  155. int
  156. MPEG_next(IPTR im, int n)
  157. {
  158.     short val;
  159.     long dev;
  160.  
  161.     push_globals(im);
  162.  
  163.     /* display the first frame */
  164.     MpegDisplay(cur_frame);
  165.  
  166.     fl_deactivate_all_forms();
  167.     report_level = -1;        /* completely turn off reporting */
  168.  
  169.     bit_show_form(create_form_mpg(), FL_PLACE_HOTSPOT, 1, "MPEG_Play");
  170.  
  171.     /* block until ESC is entered or done is pressed */
  172.     do
  173.       {
  174.       dev = bit_qread(&val);
  175.       }
  176.     while (!(dev == KEYBD && val == 27));
  177.  
  178.     bit_hide_form(create_form_mpg());
  179.  
  180.     /* signify all streams are done */
  181.     im->more = 0;
  182.  
  183.     /* restore some defaults */
  184.     pop_globals(im);
  185.     im->io->display(im, 0, 1);
  186.     fl_activate_all_forms();
  187.  
  188.     return 0;
  189. }
  190.  
  191. /***********************************************************************
  192.  * Play a single frame or all of them
  193.  **********************************************************************/
  194. static void
  195. MpegDisplay(VidStream * vid)
  196. {
  197.     int w, h, x, y;
  198.     long owin = winget();
  199.  
  200.     w = vid->mb_width * 16;
  201.     h = vid->mb_height * 16;
  202.  
  203.     x = (win_w - w * magfactor) / 2;
  204.     y = (win_h - h * magfactor) / 2;
  205.  
  206.     set_current_window(win_id);
  207.     reshapeviewport();
  208.     rectzoom(g_zoomx, g_zoomy);
  209.  
  210.     lrectwrite(x, y, w + x - 1, y + h - 1,
  211.            (unsigned long *) vid->current->display);
  212.  
  213.     if (double_buf)
  214.     swapbuffers();
  215.  
  216.     set_current_window(owin);
  217. }
  218.  
  219. /*******************************************************************
  220.  * Play a single frame or all frames in video stream
  221.  ******************************************************************/
  222.  
  223. static void
  224. MPEG_play(IPTR im, int all)
  225. {
  226.     short val;
  227.     long dev;
  228.     int stopit, start_frame = cur_frame_no, nf;
  229.     float rate;
  230.  
  231.     if (!all)
  232.       {
  233.       if ((cur_frame = mpeg_next_frame(1)))
  234.         {
  235.         MpegDisplay(cur_frame);
  236.         cur_frame_no++;
  237.         update_frame_number();
  238.         }
  239.       return;
  240.       }
  241.  
  242.   lpbk:            /* loop back */
  243.  
  244.     reset_time();
  245.  
  246.     /*
  247.      * try to display all frames, we stop only if 1. Stop is pressed (F1KEY)
  248.      * or 2. Done is pressed (ESC)  or 3. stream ends
  249.      */
  250.  
  251.     stopit = 0;
  252.     while (!stopit && (cur_frame = mpeg_next_frame(1)))
  253.       {
  254.       MpegDisplay(cur_frame);
  255.       cur_frame_no++;
  256.       update_frame_number();
  257.       fl_check_forms();
  258.  
  259.       /* pause if requested */
  260.       if (current_fdelay)
  261.           msleep(current_fdelay);
  262.  
  263.       stopit = (fl_qtest() &&
  264.             (((dev = bit_qread(&val)) == F1KEY && val) ||
  265.              (dev == KEYBD && val == 27)));
  266.       }
  267.  
  268.     /* get the rate only if more than 10 frames */
  269.     if ((nf = cur_frame_no - start_frame) > 0)
  270.       {
  271.       rate = nf * 1000.0 / (float) time_passed();
  272.       show_play_rate(rate);
  273.       }
  274.  
  275.     if (loop_back)
  276.       {
  277.       MPEG_rewind(im);
  278.       goto lpbk;
  279.       }
  280.  
  281.     /* remember this frame so that a redraw will show the correct frame */
  282.     fake_frame_to_bit(im);
  283.  
  284.     /* record the acutal number of frames we've got */
  285.     if (!cur_frame || cur_frame_no > actual_frames)
  286.       {
  287.       actual_frames = cur_frame_no;
  288.       fl_set_counter_bounds(fn, 1, actual_frames);
  289.       }
  290.  
  291.  
  292. }
  293.  
  294. /************************************************************************
  295.  * MPEG rewind
  296.  ***********************************************************************/
  297. static void
  298. MPEG_rewind(IPTR im)
  299. {
  300.     show_busy("");
  301.     cur_frame_no = 1;
  302.     update_frame_number();
  303.     rewind(im->fp);
  304.     set_video_stream(im->fp);
  305.     frame_re_init();
  306.     reset_mpeg_stream();
  307.     mpeg_next_frame(0);
  308.     end_busy();
  309. }
  310.  
  311. /*******************************************************************
  312.  * Seek to a particular frame n using the file positions saved
  313.  * last time
  314.  ******************************************************************/
  315.  
  316. /* ARGSUSED */
  317. static void
  318. MPEG_seek(int n)
  319. {
  320. #if 0
  321.     MPEG_rewind(imgptr);    /* rewind to the beginning   */
  322.     set_mpeg_seek(1);        /* turn off actually working */
  323.     cur_frame_no = 0;
  324.  
  325.     /* since mpeg_play will load one frame, we get one-less */
  326.     n -= 2;
  327.     while (cur_frame_no < n && cur_frame)
  328.       {
  329.       cur_frame = mpeg_next_frame(1);
  330.       cur_frame_no++;
  331.       update_frame_number();
  332.       }
  333.     /* load this frame for possible interpolation */
  334.     set_mpeg_seek(0);
  335.     cur_frame = mpeg_next_frame(1);
  336.     cur_frame_no++;
  337.     update_frame_number();
  338.     MPEG_play(imgptr, 0);
  339. #else
  340.     M_err("MPEGSeek", "not implemented");
  341.     update_frame_number();
  342. #endif
  343. }
  344.  
  345. /*********************************************************************
  346.  * Convert mpeg frame to bit image to handle redraw correctly
  347.  ********************************************************************/
  348.  
  349. /* fake current bit image via matrix pointer manipulations */
  350. static void
  351. fake_frame_to_bit(IPTR im)
  352. {
  353.     if (cur_frame && cur_frame->current)
  354.       {
  355.       make_mat(im->mraster, cur_frame->current->display,
  356.            im->h, im->w, im->esize);
  357.       im->raster = cur_frame->current->display;
  358.       }
  359.  
  360. }
  361.  
  362. /* Do real raster movement */
  363. static void
  364. frame_to_bit(IPTR im)
  365. {
  366.     if (cur_frame && cur_frame->current && cur_frame->current->display)
  367.     memcpy(im->raster, cur_frame->current->display,
  368.            im->w * im->h * im->esize);
  369. }
  370.  
  371. /**********************************************************************
  372.  * Save and restore some global options
  373.  *********************************************************************/
  374.  
  375. static float oldmagx, oldmagy;    /* orignal zoom factors  */
  376. static int oldreport;        /* original report level */
  377.  
  378. /* Save */
  379. static void
  380. push_globals(IPTR im)
  381. {
  382.     oldmagx = g_zoomx;
  383.     oldmagy = g_zoomy;
  384.     g_zoomx = g_zoomy = magfactor;
  385.     oldreport = report_level;
  386.     oldpic = im->raster;
  387. }
  388.  
  389. /* Restore */
  390. static void
  391. pop_globals(IPTR im)
  392. {
  393.     g_zoomx = oldmagx;
  394.     g_zoomy = oldmagy;
  395.     report_level = oldreport;
  396.     im->raster = oldpic;
  397.     make_mat(im->mraster, im->raster, im->h, im->w, im->esize);
  398. }
  399.  
  400.  
  401. /***********************************************************************
  402.  * MPEG convert
  403.  ***********************************************************************/
  404.  
  405. /**** Write current frame to disk ******/
  406. static void
  407. frame_to_disk(void)
  408. {
  409.     IMG_IO *wrgb = rgb_wio[currentwrite];
  410.     /* write_image will do nasty things to im->fp, need to save it for rewind */
  411.     FILE *mpegstream = imgptr->fp;
  412.  
  413.  
  414.     if (!cur_frame || !cur_frame->current)
  415.     return;
  416.  
  417.     fake_frame_to_bit(imgptr);
  418.  
  419.     sprintf(imgptr->ofile, "frame%04d.%s", cur_frame_no,
  420.         wrgb->ext ? wrgb->ext : "");
  421.  
  422.     if (write_image(wrgb, imgptr, imgptr->ofile))
  423.     M_warn("MPEGConvert", "frame %d failed", cur_frame_no);
  424.  
  425.     imgptr->fp = mpegstream;
  426. }
  427.  
  428. static int
  429. MPEG_convert(int all)
  430. {
  431.     int stopit;
  432.     long dev;
  433.     short val;
  434.  
  435.     if (!all)
  436.       {
  437.       frame_to_disk();
  438.       return 0;
  439.       }
  440.  
  441.     /* Convert all frames, starting from current frame */
  442.     do
  443.       {
  444.       frame_to_disk();
  445.       cur_frame = mpeg_next_frame(1);
  446.       if (cur_frame && cur_frame->current)
  447.           cur_frame_no++;
  448.       update_frame_number();
  449.       fl_check_forms();
  450.  
  451.       stopit = (fl_qtest() &&
  452.             (((dev = bit_qread(&val)) == F1KEY && val) ||
  453.              (dev == KEYBD && val == 27)));
  454.       }
  455.     while (cur_frame && !stopit);
  456.     return 0;
  457. }
  458.  
  459. /**********************************************************************
  460.  * GUI stuff
  461.  *
  462.  *********************************************************************/
  463.  
  464. static FL_FORM *mpg;
  465. static FL_OBJECT *conv_grp, *convt_1, *convt_all;
  466.  
  467. /**** Temporily disable conversion request while displaying ***/
  468. static void
  469. disable_conversion(void)
  470. {
  471.     fl_deactivate_object(conv_grp);
  472.     fl_set_object_lcol(convt_1, FL_INACTIVE);
  473.     fl_set_object_lcol(convt_all, FL_INACTIVE);
  474. }
  475.  
  476. /****  re-enable conversion request *******/
  477. static void
  478. enable_conversion(void)
  479. {
  480.     fl_set_object_lcol(convt_1, FL_BLACK);
  481.     fl_set_object_lcol(convt_all, FL_BLACK);
  482.     fl_activate_object(conv_grp);
  483. }
  484.  
  485.  
  486. /*** Disable seeking ***/
  487. static FL_OBJECT *framecntl, *frmtitle;
  488. static FL_OBJECT *frcnb[5];
  489. static void
  490. disable_frame_seek(void)
  491. {
  492.     FL_OBJECT **q = frcnb;
  493.  
  494.     fl_deactivate_object(framecntl);
  495.  
  496.     while (*q)
  497.       {
  498.       fl_set_object_lcol(*q, FL_INACTIVE);
  499.       q++;
  500.       }
  501.  
  502.     fl_set_object_lcol(frmtitle, FL_INACTIVE);
  503. }
  504.  
  505. static void
  506. enable_frame_seek(void)
  507. {
  508.     FL_OBJECT **q = frcnb;
  509.  
  510.     fl_set_object_lcol(frmtitle, FL_RED);
  511.     while (*q)
  512.       {
  513.       fl_set_object_lcol(*q, FL_BLACK);
  514.       q++;
  515.       }
  516.     fl_activate_object(framecntl);
  517. }
  518.  
  519. /*** Report current frame number *************/
  520.  
  521. static void
  522. update_frame_number(void)
  523. {
  524.     fl_set_counter_value(fn, cur_frame_no);
  525. }
  526.  
  527. /**** Finish up GUI stuff ********************/
  528.  
  529. /* ARGSUSED */
  530. static void
  531. finish_it(FL_OBJECT * ob, long q)
  532. {
  533.     fl_qenter(KEYBD, 27);
  534. }
  535.  
  536. /************ All frames related ******************/
  537.  
  538. /*** Stop whatever we are doing now ***/
  539.  
  540. /* ARGSUSED */
  541. static void
  542. stop_cb(FL_OBJECT * ob, long q)
  543. {
  544.     loop_back = 0;
  545.     fl_qenter(F1KEY, 10);
  546. }
  547.  
  548. /** Continously play until interruped by STOP. noloop if q is true */
  549. /* ARGSUSED */
  550. static void
  551. nopause_cb(FL_OBJECT * ob, long q)
  552. {
  553.     fl_freeze_form(mpg);
  554.     disable_conversion();
  555.     disable_frame_seek();
  556.     fl_unfreeze_form(mpg);
  557.  
  558.     loop_back = !q;
  559.  
  560.     MPEG_play(imgptr, 1);
  561.  
  562.     fl_freeze_form(mpg);
  563.     enable_conversion();
  564.     enable_frame_seek();
  565.     fl_unfreeze_form(mpg);
  566. }
  567.  
  568.  
  569. /** Play a single frame ***/
  570. /* ARGSUSED */
  571. static void
  572. step_cb(FL_OBJECT * ob, long q)
  573. {
  574.     MPEG_play(imgptr, 0);
  575. }
  576.  
  577. /* Play last frame again */
  578. /* ARGSUSED */
  579. static void
  580. prev_cb(FL_OBJECT * ob, long q)
  581. {
  582.     MPEG_seek(cur_frame_no - 1);
  583.     MPEG_play(imgptr, 0);
  584. }
  585.  
  586. /** Rewind the video stream **/
  587. /* ARGSUSED */
  588. static void
  589. rewind_cb(FL_OBJECT * ob, long q)
  590. {
  591.     MPEG_rewind(imgptr);
  592. }
  593.  
  594. struct frame_cntl
  595. {
  596.     const char *name;
  597.     void (*cb) (FL_OBJECT *, long);
  598.     int col;
  599. };
  600.  
  601. static struct frame_cntl frame_cb[] =
  602. {
  603.     {"PrevFrame", prev_cb, FL_YELLOW},
  604.     {"NextFrame", step_cb, FL_GREEN},
  605.     {"Rewind", rewind_cb, FL_YELLOW},
  606.     {"Play&Loop", nopause_cb, FL_RED}
  607. };
  608.  
  609.  
  610. /************ Conversion to other formats **********/
  611.  
  612. static void
  613. init_output_formats(FL_OBJECT * ob)
  614. {
  615.     int i, j;
  616.  
  617.     /* gather all output formats */
  618.     init_w_formats();
  619.  
  620.     /* collect all RGB capable formats */
  621.     for (i = j = 0; i < totalwrite; i++)
  622.       {
  623.       /*
  624.        * don't know about mpeg spec, is gray mpeg supported ? and in that
  625.        * case, replace is_rgba with IS_CPACK
  626.        */
  627.  
  628.       if (IS_RGBA(wio[i]) || (wio[i]->type == T_FLEX))
  629.           rgb_wio[j++] = wio[i];
  630.       }
  631.  
  632.     total_rgbwrite = j;
  633.  
  634.     fl_clear_choice(ob);
  635.     for (i = 0; i < total_rgbwrite; i++)
  636.     fl_addto_choice(ob, rgb_wio[i]->key);
  637.     fl_set_choice(ob, currentwrite + 1);
  638. }
  639.  
  640. /* ARGSUSED */
  641. static void
  642. wfmt_cb(FL_OBJECT * ob, long q)
  643. {
  644.     currentwrite = fl_get_choice(ob) - 1;
  645. }
  646.  
  647. /********* Must block while writing ***************/
  648. /* ARGSUSED */
  649. static void
  650. convert_cb(FL_OBJECT * ob, long q)
  651. {
  652.     if (q)
  653.       {
  654.       fl_freeze_form(mpg);
  655.       disable_conversion();
  656.       disable_frame_seek();
  657.       fl_unfreeze_form(mpg);
  658.       }
  659.  
  660.     MPEG_convert(q);
  661.  
  662.     if (q)
  663.       {
  664.       fl_freeze_form(mpg);
  665.       enable_conversion();
  666.       enable_frame_seek();
  667.       fl_unfreeze_form(mpg);
  668.       }
  669. }
  670.  
  671.  
  672. /************ Display parameters ***************/
  673.  
  674. /*** Maginification factors ************/
  675.  
  676. static const char *magf[] =
  677. {
  678.     "1x1", "2x2", "3x3", "4x4", "5x5"
  679. };
  680.  
  681. /* delay between each frame, in milli-second */
  682.  
  683. static int fdelay[] =
  684. {
  685.     0, 10, 20, 30, 40, 50, 100, 500, 1000
  686. };
  687.  
  688. /* ARGSUSED */
  689. static void
  690. mag_cb(FL_OBJECT * ob, long q)
  691. {
  692.     static int lastf = 2;
  693.  
  694.     magfactor = fl_get_choice(ob);
  695.     g_zoomx = g_zoomy = magfactor;
  696.  
  697.     if (cur_frame)
  698.       {
  699.       /*
  700.        * if last magifiation factor is greater than requested, clear
  701.        * screen, else look bad in double buffer mode
  702.        */
  703.  
  704.       if (lastf > magfactor)
  705.           clear_screen(win_id, 0);
  706.  
  707.       MpegDisplay(cur_frame);
  708.  
  709.       if (lastf > magfactor)
  710.           clear_screen(win_id, 0);
  711.       lastf = magfactor;
  712.       }
  713. }
  714.  
  715. /* ARGSUSED */
  716. static void
  717. delay_cb(FL_OBJECT * ob, long q)
  718. {
  719.     int i = fl_get_choice(ob) - 1;
  720.  
  721.     if (i >= 0)
  722.     current_fdelay = fdelay[i];
  723. }
  724.  
  725. /* ARGSUSED */
  726. static void
  727. frame_seek_cb(FL_OBJECT * ob, long q)
  728. {
  729.     int n = fl_get_counter_value(ob);
  730.  
  731.     if (n == cur_frame_no)    /* this happens if at end or beginning */
  732.     return;
  733.  
  734.     MPEG_seek(n);
  735. }
  736.  
  737.  
  738. static FL_OBJECT *playrate;
  739. static void
  740. show_play_rate(float rate)
  741. {
  742.     char srate[25];
  743.  
  744.     sprintf(srate, "%.2ff/s", rate);
  745.     fl_set_object_label(playrate, srate);
  746. }
  747.  
  748.  
  749. static FL_FORM *
  750. create_form_mpg(void)
  751. {
  752.     FL_OBJECT *obj;
  753.     int i;
  754.     float x, y, dx, dy;
  755.     int nbt = sizeof(frame_cb) / sizeof(frame_cb[0]);
  756.  
  757.     if (mpg)
  758.     return mpg;
  759.  
  760.     mpg = fl_bgn_form(FL_UP_BOX, 280.0, 235.0);
  761.     obj = fl_add_button(FL_HB, 0.0, 0.0, 280.0, 235.0, "");
  762.     fl_set_call_back(obj, help_cb, HELP_MPEG);
  763.     obj = fl_add_text(FL_NT, 40.0, 200.0, 200.0, 20.0, "MPEG control");
  764.     fl_set_object_lcol(obj, 4);
  765.     fl_set_object_lsize(obj, 16.000000);
  766.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  767.  
  768.     /* overall controls * */
  769.     obj = fl_add_button(FL_NB, 190.0, 15.0, 75.0, 25.0, "Done");
  770.     fl_set_object_lsize(obj, 10.0);
  771.     fl_set_call_back(obj, finish_it, 0);
  772.     fl_set_object_color(obj, FL_MAGIC1, FL_YELLOW);
  773.  
  774.     obj = fl_add_button(FL_NB, 190.0, 45.0, 75.0, 25.0, "Stop");
  775.     fl_set_object_lsize(obj, 10.0);
  776.     fl_set_call_back(obj, stop_cb, 0);
  777.     fl_set_object_color(obj, FL_MAGIC1, FL_YELLOW);
  778.  
  779.     /* conversion group */
  780.     conv_grp = fl_bgn_group();
  781.  
  782.     convt_1 = obj = fl_add_button(FL_NB, 190.0, 130.0, 75.0, 25.0, "Convert");
  783.     fl_set_object_lsize(obj, 10.0);
  784.     fl_set_object_color(obj, FL_MAGIC1, FL_YELLOW);
  785.     fl_set_call_back(obj, convert_cb, 0);
  786.     convt_all = obj = fl_add_button(FL_NB, 190.0, 95.0, 75.0, 25.0, "ConvertAll");
  787.     fl_set_object_lsize(obj, 10.0);
  788.     fl_set_object_color(obj, FL_MAGIC1, FL_RED);
  789.     fl_set_call_back(obj, convert_cb, 1);
  790.  
  791.     /* all formats */
  792.     obj = fl_add_choice(FL_NORMAL_CHOICE, 190.0, 165.0, 65.0, 20.0, "");
  793.     fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
  794.     fl_set_choice_fontsize(obj, 10.0);
  795.     init_output_formats(obj);
  796.     fl_set_call_back(obj, wfmt_cb, 0);
  797.  
  798.     fl_end_group();
  799.  
  800.     /********** Frame controls *************/
  801.  
  802.     framecntl = fl_bgn_group();
  803.  
  804.     obj = fl_add_box(FL_SHADOW_BOX, 10.0, 10.0, 170.0, 145.0, "");
  805.  
  806.     frmtitle = obj = fl_add_text(FL_NT, 40.0, 135.0, 120.0, 15.0,
  807.                  "FrameControl");
  808.     fl_set_object_lcol(obj, 1);
  809.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  810.     fl_set_object_lsize(obj, 12.0);
  811.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  812.  
  813.     x = 20.0;
  814.     y = 70.0;
  815.     dx = 75.0;
  816.     dy = 25.0;
  817.  
  818.     for (i = 0; i < nbt; i += 2, x = 20, y -= dy)
  819.       {
  820.       frcnb[i] = obj = fl_add_button(FL_NB, x, y, dx, dy, frame_cb[i].name);
  821.       fl_set_object_lsize(obj, 10.0);
  822.       fl_set_object_color(obj, FL_MAGIC1, frame_cb[i].col);
  823.       fl_set_call_back(obj, frame_cb[i].cb, 0);
  824.       x += dx;
  825.       if ((i + 1) < nbt)
  826.         {
  827.         frcnb[i + 1] = obj = fl_add_button(FL_NB, x, y, dx, dy,
  828.                            frame_cb[i + 1].name);
  829.         fl_set_object_lsize(obj, 10.0);
  830.         fl_set_object_color(obj, FL_MAGIC1, frame_cb[i + 1].col);
  831.         fl_set_call_back(obj, frame_cb[i + 1].cb, 0);
  832.         }
  833.       }
  834.  
  835.     /* a large one for play */
  836.     frcnb[i] = obj = fl_add_button(FL_NB, 20, y - 3, 2 * dx, dy + 2, "Play");
  837.     fl_set_object_lsize(obj, 10.0);
  838.     fl_set_object_color(obj, FL_MAGIC1, FL_GREEN);
  839.     fl_set_call_back(obj, nopause_cb, 1);
  840.     fl_set_form_hotspot(mpg, 20.0 + dx, (y - 3) + 0.5 * dy);
  841.  
  842.     /* current frame number */
  843.     fn = obj = fl_add_counter(FL_NC, 20.0, 100.0, 150.0, 25.0, "");
  844.     fl_set_object_lsize(obj, 10.0);
  845.     /* properties */
  846.     fl_set_counter_precision(obj, 0);
  847.     fl_set_counter_bounds(obj, 1, 2000);
  848.     fl_set_counter_value(obj, 1);
  849.     fl_set_counter_step(obj, SEEKSMALL, SEEKLARGE);
  850.     fl_set_call_back(obj, frame_seek_cb, 0);
  851.     fl_end_group();
  852.  
  853.  
  854.     dy = 20;
  855.     dx = 55;
  856.     x = 10.0;
  857.     y = 165.0;
  858.     /***** Magification factors ********/
  859.     obj = fl_add_choice(FL_NORMAL_CHOICE, x, y, dx, dy, "");
  860.     fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
  861.     fl_set_choice_fontsize(obj, 10.0);
  862.     for (i = 0; i < sizeof(magf) / sizeof(magf[0]); i++)
  863.     fl_addto_choice(obj, magf[i]);
  864.     fl_set_choice(obj, magfactor);
  865.     fl_set_call_back(obj, mag_cb, 0);
  866.     x += dx + 2;
  867.  
  868.     /****** Delay factors **********/
  869.     obj = fl_add_choice(FL_NORMAL_CHOICE, x, y, dx, dy, "");
  870.     fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
  871.     fl_set_object_lsize(obj, 10.0);
  872.     for (i = 0; i < sizeof(fdelay) / sizeof(fdelay[0]); i++)
  873.     fl_addto_choice(obj, itoa(fdelay[i]));
  874.     fl_set_choice(obj, 1);    /* default no delay */
  875.     fl_set_call_back(obj, delay_cb, 0);
  876.  
  877.     x += dx + 2;
  878.  
  879.     /***** final statistics *******/
  880.     playrate = obj = fl_add_text(FL_NT, x, y, dx, dy, "? f/s");
  881.     fl_set_object_boxtype(obj, FL_BORDER_BOX);
  882.     fl_set_object_lsize(obj, 10.0);
  883.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  884.  
  885.     fl_end_form();
  886.     return mpg;
  887. }
  888.  
  889. #endif
  890.